package xin.xihc.jba.sql;

import xin.xihc.jba.scan.TableManager;
import xin.xihc.jba.sql.join.Join;
import xin.xihc.utils.common.CommonUtil;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import static xin.xihc.jba.sql.SqlConstants.*;

/**
 * Select语句生成器
 *
 * @author Leo.Xi
 * @date 2020/1/14
 * @since 1.0
 **/
public class Select implements SqlType {

    /** COLUMN 列 */
    private final List<String> columns = new LinkedList<>();
    /** TABLE 表 */
    private final List<String> tables = new LinkedList<>();
    /** JOIN 表 */
    private final List<Join> joins = new LinkedList<>();
    /** 排序字段列表 */
    private final List<String> orderBys = new LinkedList<>();
    private KV kv = new KV("s");
    private Where where;
    private String groupBy;// 分组
    private Having having;

    private Select() {
    }

    /**
     * 查询的表的实体类
     *
     * @param clazz 实体类
     * @return Select
     */
    public static Select from(Class<?> clazz) {
        return from(clazz, null);
    }

    /**
     * 查询的表的实体类
     *
     * @param clazz 实体类
     * @return Select
     */
    public static Select from(Class<?> clazz, String as) {
        Select select = new Select();
        if (CommonUtil.isNotNullEmpty(as)) {
            select.tables.add(TableManager.getTable(clazz)
                                          .getTableName() + AS + as);
        } else {
            select.tables.add(TableManager.getTable(clazz)
                                          .getTableName());
        }
        return select;
    }

    /**
     * 查询的表的实体类
     *
     * @param tables 表名
     * @return
     */
    public static Select from(String... tables) {
        Select select = new Select();
        select.tables.addAll(Arrays.asList(tables));
        return select;
    }

    /**
     * 查询的表的实体类里的所有属性
     *
     * @param clazz 表对应的实体类
     * @return this
     */
    public Select select(Class<?> clazz) {
        return select(clazz, null);
    }

    /**
     * 查询的表的实体类里的所有属性
     *
     * @param clazz 表对应的实体类
     * @return this
     */
    public Select select(Class<?> clazz, String prefix) {
        columns.addAll(TableManager.getColumnNames(clazz, prefix, null));
        return this;
    }

    /**
     * 查询的列名
     *
     * @param columns 列的列表
     * @return this
     */
    public Select select(String... columns) {
        this.columns.addAll(Arrays.asList(columns));
        return this;
    }

    /**
     * select *
     *
     * @return this
     */
    public Select select() {
        if (this.columns.size() < 1) {
            this.columns.add("*");
        }
        return this;
    }

    /**
     * join操作
     *
     * @param join 具体的join
     * @return this
     * @author Leo.Xi
     * @date 2020/8/23
     * @since 0.0.1
     */
    public Select join(Join join) {
        this.joins.add(join);
        return this;
    }

    /**
     * 生成新的where条件语句
     *
     * @return Where
     */
    public Where where() {
        if (null == this.where) {
            this.where = new Where(this.kv);
        }
        return this.where;
    }

    /**
     * 分组
     *
     * @param by 分组
     * @return this
     * @author Leo.Xi
     * @date 2020/8/23
     * @since 0.0.1
     */
    public Select groupBy(String by) {
        this.groupBy = by;
        return this;
    }

    /**
     * 生成新的Having条件语句
     *
     * @return Having
     */
    public Having having() {
        this.having = new Having(this.kv);
        return this.having;
    }

    /**
     * 排序条件
     *
     * @param orders 排序条件
     * @return this
     */
    public Select orderBy(String... orders) {
        this.orderBys.addAll(Arrays.asList(orders));
        return this;
    }

    public KV getKv() {
        return this.kv;
    }

    /**
     * 转为SQL语句
     *
     * @return sql
     * @author Leo.Xi
     * @date 2020/1/14
     * @since 0.0.1
     */
    @Override
    public String toSql() {
        StringBuilder sql = new StringBuilder(action());
        sql.append(String.join(",", this.columns))
           .append(FROM)
           .append(String.join(",", this.tables));
        for (Join join : this.joins) {
            sql.append(join.toSql());
        }
        if (this.where != null) {
            sql.append(this.where.toSql());
        }
        if (this.groupBy != null) {
            sql.append(GROUP_BY).append(this.groupBy);
        }
        if (this.having != null) {
            sql.append(this.having.toSql());
        }
        if (this.orderBys.size() > 0) {
            sql.append(ORDER_BY)
               .append(String.join(",", this.orderBys));
        }
        return sql.toString();
    }

    /**
     * 操作类型
     *
     * @return SELECT、WHERE、UPDATE、ORDER BY、
     * @author Leo.Xi
     * @date 2020/1/18
     * @since 0.0.1
     */
    @Override
    public String action() {
        return SELECT;
    }

}